module hand_dp_ram_rd_ctrl #(
    parameter DEPTH  = 16,
	parameter DATA_W = 8,
    parameter INFO_W = 8,
	parameter RAM_DL = 2
)(
	input                      clk,
	input                      rst_n,
	
	input  					   ar_valid,
	output 					   ar_ready,
	input  [$clog2(DEPTH) -1:0]ar_addr,
    input  [INFO_W        -1:0]ar_info,
	
	output					   r_valid,
	input					   r_ready,
	output [DATA_W        -1:0]r_data,
    output [INFO_W        -1:0]r_info,
	
	output 					   ram_renc,
	output [$clog2(DEPTH) -1:0]ram_raddr,
	input  [DATA_W        -1:0]ram_r_data
);

localparam DEPTH_W = $clog2(DEPTH);

// ======================================================
// bw_pipe inst
// ======================================================
wire                     ram_out_pipe0_valid, ram_out_pipe0_ready;
wire [DATA_W+INFO_W -1:0]ram_out_pipe0_data;
wire                     ram_out_pipe1_valid, ram_out_pipe1_ready;
wire [DATA_W+INFO_W -1:0]ram_out_pipe1_data;

bw_pipe #(.WIDTH(DATA_W+INFO_W))
u_ram_out_pipe0(
    .clk           (clk),
    .rst_n         (rst_n),
    .data_in_valid (ram_out_pipe0_valid),
    .data_in       (ram_out_pipe0_data),
    .data_in_ready (ram_out_pipe0_ready),
    .data_out_valid(ram_out_pipe1_valid),
    .data_out      (ram_out_pipe1_data),
    .data_out_ready(ram_out_pipe1_ready)
);

bw_pipe #(.WIDTH(DATA_W+INFO_W))
u_ram_out_pipe1(
    .clk           (clk),
    .rst_n         (rst_n),
    .data_in_valid (ram_out_pipe1_valid),
    .data_in       (ram_out_pipe1_data),
    .data_in_ready (ram_out_pipe1_ready),
    .data_out_valid(r_valid),
    .data_out      ({r_data, r_info}),
    .data_out_ready(r_ready)
);

// ======================================================
// renc dff and info dff
// ======================================================
wire              ram_renc_ff1, ram_renc_ff2;
wire [INFO_W -1:0]ar_info_ff1, ar_info_ff2;

dffr u_ram_renc_ff1(
    .clk    (clk),
    .rst_n  (rst_n),
    .d      (ram_renc),
    .q      (ram_renc_ff1)
);

dffr u_ram_renc_ff2(
    .clk    (clk),
    .rst_n  (rst_n),
    .d      (ram_renc_ff1),
    .q      (ram_renc_ff2)
);

dffe #(.WIDTH(INFO_W))
u_ar_info_ff1(
    .clk    (clk),
    .d      (ar_info),
    .en     (ram_renc),
    .q      (ar_info_ff1)
);

dffe #(.WIDTH(INFO_W))
u_ar_info_ff2(
    .clk    (clk),
    .d      (ar_info_ff1),
    .en     (ram_renc_ff1),
    .q      (ar_info_ff2)
);

// ======================================================
// logic
// ======================================================
wire [3 -1:0]empty_cnt = !ram_renc_ff1 + !ram_renc_ff2 + ram_out_pipe0_ready + ram_out_pipe1_ready + r_ready;

assign ram_renc            = (ar_valid && ar_ready);
assign ram_raddr           = ar_addr;
assign ram_out_pipe0_valid = ram_renc_ff2;
assign ram_out_pipe0_data  = {ram_r_data, ar_info_ff2};
assign ar_ready            = (empty_cnt >= 3'd3);

endmodule
